PyTorch教程:Tensor的使用介绍

您所在的位置:网站首页 pytorch tensor转为numpy PyTorch教程:Tensor的使用介绍

PyTorch教程:Tensor的使用介绍

2023-06-18 18:51| 来源: 网络整理| 查看: 265

目录

创建Tensor

Tensor的shape

tensor数据类型

PyTorch tensor的数学和逻辑运算

Tensor Broadcasting广播

复制tensor

改变维数

和Numpy的转换

Tensor是PyTorch中心的数据抽象,本文深度详细介绍PyTorch的torch.Tensor类。包括创建Tensor的方法,Tensor的shape属性,tensor的数据类型和数学运算,tensor的广播机制,克隆tensor,改变tensor的维数,将tensor转换维Numpy的ndarray以及将ndarray转为为tensor。

创建Tensor import torch import math x = torch.empty(3, 4) print(type(x)) print(x)

使用torch模块的工厂函数torch.empty()创建一个tensor,该tensor是2维,有3行4列。返回的对象类型是torch.Tensor,是torch.FloatTensor的别名。默认情况下PyTorch tensor是32bit的浮点数。你可能会看到打印的tensor是像随机数的值,这是因为torch.empty为tensor调用内存分配,但是并没有初始化其值,你看到的是在分配内存时的值。

1维的tensor叫做向量vector,2维的tensor叫做矩阵matrix,高于两维一般称其为tensor

更多情况下,你想用一些值来初始化tensor,通常情况下将初始化为全0,全1或者随机值。torch模块为这些初始化提供了工厂函数:

zeros = torch.zeros(2, 3) print(zeros) ones = torch.ones(2, 3) print(ones) torch.manual_seed(1729) random = torch.rand(2, 3) print(random)

torch.manual_seed()用于手动设置随机数生成器的种子,保证使用torch模块随机数工厂函数torch.rand()的代码的可再现性

torch.manual_seed(1729) random1 = torch.rand(2, 3) print(random1) random2 = torch.rand(2, 3) print(random2) torch.manual_seed(1729) random3 = torch.rand(2, 3) print(random3) random4 = torch.rand(2, 3) print(random4)

输出:

tensor([[0.3126, 0.3791, 0.3087], [0.0736, 0.4216, 0.0691]]) tensor([[0.2332, 0.4047, 0.2162], [0.9927, 0.4128, 0.5938]]) tensor([[0.3126, 0.3791, 0.3087], [0.0736, 0.4216, 0.0691]]) tensor([[0.2332, 0.4047, 0.2162], [0.9927, 0.4128, 0.5938]])

最后一种创建tensor的方法:

some_constants = torch.tensor([[3.1415926, 2.71828], [1.61803, 0.0072897]]) print(some_constants) some_integers = torch.tensor((2, 3, 5, 7, 11, 13, 17, 19)) print(some_integers) more_integers = torch.tensor(((2, 4, 6), [3, 6, 9])) print(more_integers) Tensor的shape

我们经常对两个或者多个tensor执行操作,这些tensor需要是相同的shape,也就是有相同的维数,并且在各个维度上的cells数目相同,我们可以使用torch.*_liek()方法,比如torch.empty_like(),torch.zeros_like(), torch.ones_like(),toch.rand_like()

x = torch.empty(2, 2, 3) print(x.shape) print(x) empty_like_x = torch.empty_like(x) print(empty_like_x.shape) print(empty_like_x) zeros_like_x = torch.zeros_like(x) print(zeros_like_x.shape) print(zeros_like_x) ones_like_x = torch.ones_like(x) print(ones_like_x.shape) print(ones_like_x) rand_like_x = torch.rand_like(x) print(rand_like_x.shape) print(rand_like_x) tensor数据类型

通过在torch的工厂函数输入参数中指定dtype的值,给创建的tensor指定数据类型,默认的数据类型是torch.float(32位浮点),常见的数据类型如下 Available data types include:

torch.booltorch.int8torch.uint8torch.int16torch.int32torch.int64torch.halftorch.floattorch.doubletorch.bfloat PyTorch tensor的数学和逻辑运算 ones = torch.zeros(2, 2) + 1 twos = torch.ones(2, 2) * 2 threes = (torch.ones(2, 2) * 7 - 1) / 2 fours = twos ** 2 sqrt2s = twos ** 0.5 print(ones) print(twos) print(threes) print(fours) print(sqrt2s)

输出:

tensor([[1., 1.], [1., 1.]]) tensor([[2., 2.], [2., 2.]]) tensor([[3., 3.], [3., 3.]]) tensor([[4., 4.], [4., 4.]]) tensor([[1.4142, 1.4142], [1.4142, 1.4142]]) Tensor Broadcasting广播

一般情况下进行算术运算的tensor的shape必须相同,但是有一种例外情况是tensor的广播。

rand = torch.rand(2, 4) doubled = rand * (torch.ones(1, 4) * 2) print(rand) print(doubled)

输出:

tensor([[0.6146, 0.5999, 0.5013, 0.9397], [0.8656, 0.5207, 0.6865, 0.3614]]) tensor([[1.2291, 1.1998, 1.0026, 1.8793], [1.7312, 1.0413, 1.3730, 0.7228]]) a = torch.ones(4, 3, 2) b = a * torch.rand( 3, 2) # 3rd & 2nd dims identical to a, dim 1 absent print(b) c = a * torch.rand( 3, 1) # 3rd dim = 1, 2nd dim identical to a print(c) d = a * torch.rand( 1, 2) # 3rd dim identical to a, 2nd dim = 1 print(d)

输出:

tensor([[[0.6493, 0.2633], [0.4762, 0.0548], [0.2024, 0.5731]], [[0.6493, 0.2633], [0.4762, 0.0548], [0.2024, 0.5731]], [[0.6493, 0.2633], [0.4762, 0.0548], [0.2024, 0.5731]], [[0.6493, 0.2633], [0.4762, 0.0548], [0.2024, 0.5731]]]) tensor([[[0.7191, 0.7191], [0.4067, 0.4067], [0.7301, 0.7301]], [[0.7191, 0.7191], [0.4067, 0.4067], [0.7301, 0.7301]], [[0.7191, 0.7191], [0.4067, 0.4067], [0.7301, 0.7301]], [[0.7191, 0.7191], [0.4067, 0.4067], [0.7301, 0.7301]]]) tensor([[[0.6276, 0.7357], [0.6276, 0.7357], [0.6276, 0.7357]], [[0.6276, 0.7357], [0.6276, 0.7357], [0.6276, 0.7357]], [[0.6276, 0.7357], [0.6276, 0.7357], [0.6276, 0.7357]], [[0.6276, 0.7357], [0.6276, 0.7357], [0.6276, 0.7357]]])

tensor的大多数二元操作将返回第三个新的tensor,例如,c = a * b,a和b是两个tensor,新的tensor c将占据不同与a和b的内存区域。 有时候,当你做元素操作时希望丢弃中间结果,可以使用单下划线_的函数版本,可就地改变tensor。

a = torch.ones(2, 2) b = torch.rand(2, 2) print('Before:') print(a) print(b) print('\nAfter adding:') print(a.add_(b)) print(a) print(b) print('\nAfter multiplying') print(b.mul_(b)) print(b)

输出:

Before: tensor([[1., 1.], [1., 1.]]) tensor([[0.0905, 0.4485], [0.8740, 0.2526]]) After adding: tensor([[1.0905, 1.4485], [1.8740, 1.2526]]) tensor([[1.0905, 1.4485], [1.8740, 1.2526]]) tensor([[0.0905, 0.4485], [0.8740, 0.2526]]) After multiplying tensor([[0.0082, 0.2012], [0.7638, 0.0638]]) tensor([[0.0082, 0.2012], [0.7638, 0.0638]])

需要注意的是in-place算术函数是torch.Tensor对象的方法,而不是想许多其他函数一样附加在torch模块。

复制tensor

与Python中的任何对象一样,将tensor赋值给变量,会使变量是tensor的标签,而不是拷贝它。 当需要分开拷贝数据时,可以使用clone()方法。

a = torch.ones(2, 2) b = a.clone() assert b is not a # 在内存中是不同的对象 print(torch.eq(a, b)) # 但是所存储的内容相同 a[0][1] = 561 # a 改变了 print(b) # 但b仍然是1

在许多情况下,如果你的模型在forward()方法中有多种计算路径。并且原始的tensor和克隆的tensor都对模型的输出有贡献,为了使能模型学习,你希望autograd在这两种tensor上开启。如果原始tensor的autograd开启了,你将得到你所希望的结果。 另一方面,如果在做计算时,原始tensor和克隆的tensor都不需要跟踪梯度,只要原始tensor的autograd没有开启,你将得到你所希望的结果。 第三种情况是,设想你在模型的forward()函数中执行计算,梯度是默认开启的,你想拉一些中间值去生成新的特性,这种情况下,你不想克原始tensor的克隆拷贝跟踪梯度--当autograd的历史跟踪关闭时性能将提高。这种情况下,可以在原始tensor上使用.detech()方法

a = torch.rand(2, 2, requires_grad=True) # 开启autograd print(a) b = a.clone() print(b) c = a.detach().clone() print(c) print(a)

输出:

tensor([[0.6545, 0.4144], [0.0696, 0.4648]], requires_grad=True) tensor([[0.6545, 0.4144], [0.0696, 0.4648]], grad_fn=) tensor([[0.6545, 0.4144], [0.0696, 0.4648]]) tensor([[0.6545, 0.4144], [0.0696, 0.4648]], requires_grad=True) 改变维数

有时候我们需要改变维数,例如传递单个输入实例到模型。Pytorch模型通常期望是batch的输入。假设你的模型处理3x226x226的图像(3个颜色通道,226x226的尺寸),输入的tensor的shape是(3,226,226),但是模型期望的输入是(N,3,226,226),N表示一个batch的图像数目,如果将输入转换为包含一个图像的batch呢?

a = torch.rand(3, 226, 226) b = a.unsqueeze(0) print(a.shape) print(b.shape)

输出:

torch.Size([3, 226, 226]) torch.Size([1, 3, 226, 226])

还可以使用squeeze()将batch转换为non-batch计算

a = torch.rand(1, 20) print(a.shape) print(a) b = a.squeeze(0) print(b.shape) print(b) c = torch.rand(2, 2) print(c.shape) d = c.squeeze(0) print(d.shape) d = c.squeeze(1) print(d.shape)

输出:

torch.Size([1, 20]) tensor([[0.3118, 0.9180, 0.7293, 0.5351, 0.5078, 0.8012, 0.5088, 0.3142, 0.8068, 0.6503, 0.4621, 0.6882, 0.7282, 0.9156, 0.4836, 0.1451, 0.7946, 0.4126, 0.1625, 0.9214]]) torch.Size([20]) tensor([0.3118, 0.9180, 0.7293, 0.5351, 0.5078, 0.8012, 0.5088, 0.3142, 0.8068, 0.6503, 0.4621, 0.6882, 0.7282, 0.9156, 0.4836, 0.1451, 0.7946, 0.4126, 0.1625, 0.9214]) torch.Size([2, 2]) torch.Size([2, 2]) torch.Size([2, 2])

可以看到使用squeeze()后,2维的tensor变成了1维的tensor,a的外层比b多一个方括号[]

squeeze()只能是改变宽度为1的维,当在c中尺寸是2的维上使用squeeze()时,并不会有任何改变。

有时候希望彻底改变tensor的形状,但保留其元素和内容不变。 出现这种需求的一种情况是在卷积层和线性层的接口,通常发生在图像分类模型。一个卷积核产生的tensor的形状是特征图的个数宽度高度,但是紧接着的线性层希望一维的输入。reshape()将为你做这一工作。

output3d = torch.rand(6, 20, 20) print(output3d.shape) input1d = output3d.reshape(6 * 20 * 20) print(input1d.shape) # can also call it as a method on the torch module: print(torch.reshape(output3d, (6 * 20 * 20,)).shape)

输出:

torch.Size([6, 20, 20]) torch.Size([2400]) torch.Size([2400])

reshape()执行成功以后会返回tensor的一个改变的视图view,但底层的内存区域保持不变。这意味着对原来tensor的任何改变都会反映在这个tensor的视图上,除非使用clone()方法。

和Numpy的转换

当你有已经存在使用Numpy的ndarray存储的数据的机器学习或者科学的代码,你希望将这些数据表示成PyTorch tensor,利用PyTorch的GPU加速或者它用于构建机器学习模型的高效抽象能力。可以很容的在ndarray和PyTorch tensor直接切换。使用torch.from_numpy()可以将numpy ndarray转换为tensor,使用torch.numpy()可以将tensor转换为numpy ndarray。但是tensor和numpy ndarray使用同样的内存,除非使用clone()函数。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3